import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import os from 'os';
import { execSync } from 'child_process';

export interface License {
  hardwareHash: string;
  encryptedExpiry: string; // 加密的过期时间
  signature: string;
  // 移除明文admin字段，admin信息将加密存储在签名中
}

/**
 * 获取硬件信息
 */
export function getHardwareInfo() : {
  cpuId: string;
  cpuName: string;
  macAddress: string;
} {
  try {
    const platform = os.platform();

    // 根据不同操作系统使用不同命令
    if (platform === 'win32') {
      // 1. CPU 序列号
      const cpuId = execSync(
        'powershell -NoProfile -Command "(Get-WmiObject win32_processor).ProcessorId"',
        { encoding: 'utf-8' }
      ).trim() || 'N/A';

      // 2. CPU 型号
      const cpuName = execSync(
        'powershell -NoProfile -Command "(Get-WmiObject win32_processor).Name"',
        { encoding: 'utf-8' }
      ).trim() || 'N/A';

      // 3. 取第一张已启用网卡的 MAC 地址
      const macAddress = execSync(
        'powershell -NoProfile -Command "(Get-CimInstance win32_networkadapter | Where-Object {$_.NetEnabled}).MACAddress | Select-Object -First 1"',
        { encoding: 'utf-8' }
      ).trim().toLowerCase() || 'N/A';

      return { cpuId, cpuName, macAddress };
    } 
    else if (platform === 'linux') {
      // 1. CPU 唯一标识（品牌字符串）
      const cpuId = execSync('dmidecode -t processor | grep "ID:" | head -n1', { encoding: 'utf-8' })
                    .trim()
                    .replace("ID:", "")
                    .trim();
      // 2. CPU 型号
      const cpuName = execSync("cat /host/proc/cpuinfo | grep -m1 'model name' | sed 's/.*:\s*//'", { encoding: 'utf-8' })
                      .trim();
      // 3. 以太网 MAC
      const macAddress = execSync('cat /host/sys/class/net/eth0/address', { encoding: 'utf-8' })
                      .trim();
      return { cpuId, cpuName, macAddress };
    } 
    else if (platform === 'darwin') {
      // 1. CPU 唯一标识（品牌字符串）
      const cpuId = execSync('sysctl -n machdep.cpu.brand_string', { encoding: 'utf-8' })
                    .trim()
                    .replace(/\s+/g, '-');

      // 2. CPU 型号
      const cpuName = execSync('sysctl -n machdep.cpu.brand_string', { encoding: 'utf-8' })
                      .trim();

      // 3. MAC 地址
      const macAddress = execSync(
        'networksetup -listallhardwareports | awk \'/Ethernet Address/{print $3}\' | head -n 1',
        { encoding: 'utf-8' }
      ).trim().toLowerCase();

      return { cpuId, cpuName, macAddress };
    } 
    else {
      throw new Error(`Unsupported platform: ${platform}`);
    }
  } catch (err) {
    console.error('[错误] 获取硬件信息失败:', err instanceof Error ? err.message : String(err));
    return {
      cpuId: 'N/A',
      cpuName: 'N/A',
      macAddress: 'N/A',
    };
  }
}

export function generateHardwareHash(cpuId: string, macAddress: string, cpuName: string, publicIp?: string): string {
  let raw = `${macAddress}-${cpuId}-${cpuName}`;
  if (publicIp) {
    raw += `-${publicIp}`;
  }
  console.log("原始硬件指纹", raw);
  return crypto.createHash('sha256').update(raw).digest('hex');
}

/**
 * 获取本机硬件指纹
 */
export function getHardwareHash(publicIp?: string): string {
  const { cpuId, cpuName, macAddress } = getHardwareInfo();
  let raw = `${macAddress}-${cpuId}-${cpuName}`;
  if (publicIp) {
    raw += `-${publicIp}`;
  }
  console.log("原始硬件指纹", raw);
  return crypto.createHash('sha256').update(raw).digest('hex');
}

/**
 * 使用AES加密许可证敏感信息（过期时间和管理员标识）
 */
function encryptLicenseData(expiryDate: string, admin: boolean, hardwareHash: string): string {
  // 构造包含过期时间和管理员标识的数据
  const sensitiveData = {
    expiryDate,
    admin
  };
  
  // 使用硬件哈希的前32位作为密钥
  const key = Buffer.from(hardwareHash.substring(0, 32), 'utf8');
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  
  const dataStr = JSON.stringify(sensitiveData);
  let encrypted = cipher.update(dataStr, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  
  // 将IV和加密数据组合
  return iv.toString('hex') + ':' + encrypted;
}

/**
 * 使用AES解密许可证敏感信息
 */
function decryptLicenseData(encryptedData: string, hardwareHash: string): { expiryDate: string; admin: boolean } {
  try {
    const key = Buffer.from(hardwareHash.substring(0, 32), 'utf8');
    const parts = encryptedData.split(':');
    
    if (parts.length !== 2) {
      throw new Error('Invalid encrypted format');
    }
    
    const iv = Buffer.from(parts[0], 'hex');
    const encrypted = parts[1];
    
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    
    return JSON.parse(decrypted);
  } catch (err) {
    throw new Error('Failed to decrypt license data');
  }
}

export function generateLicense(hardwareHash: string, expiryDateStr: string, admin: boolean): License {
  try {
    // 构造北京时间（东八区）23:59:59
    const bjDate = new Date(`${expiryDateStr}T23:59:59+08:00`);
    const expiryDate = bjDate.toISOString(); // 存储为UTC
    
    // 加密敏感数据（过期时间和管理员标识）
    const encryptedExpiry = encryptLicenseData(expiryDate, admin, hardwareHash);
    
    // 签名数据（包含硬件哈希和加密的敏感数据）
    const licenseData = {
      hardwareHash,
      encryptedExpiry
    };
    
    const privateKeyPath = path.resolve(process.cwd(), 'src/config/private.pem');
    const privateKey = fs.readFileSync(privateKeyPath, 'utf-8');
    
    // 签名
    const licenseStr = JSON.stringify(licenseData);
    const sign = crypto.createSign('RSA-SHA256');
    sign.update(licenseStr);
    sign.end();
    const signature = sign.sign(privateKey, 'base64');
    
    // 完整的License（不包含明文敏感信息）
    const license: License = {
      hardwareHash,
      encryptedExpiry,
      signature
    };
    
    console.log("生成的许可证", {
      ...license,
      // 仅用于调试显示，不会存储在实际License文件中
      debug: { expiryDate, admin }
    });
    
    return license;
  } catch (err) {
    console.error('[错误] 生成许可证失败:', err instanceof Error ? err.message : String(err));
    throw new Error('生成许可证失败');
  }
}

/**
 * 校验许可证
 */
export async function verifyLicense(): Promise<{ valid: boolean; reason: string; expiryDate?: string; admin?: boolean }> {
  const licensePath = path.resolve(process.cwd(), 'license.json');
  if (!fs.existsSync(licensePath)) {
    return { valid: false, reason: '未找到license.json' };
  }
  
  const license: License = JSON.parse(fs.readFileSync(licensePath, 'utf-8'));
  const { hardwareHash, encryptedExpiry, signature } = license;
  
  try {
    // 1. 校验硬件指纹
    const localHash = getHardwareHash();
    if (hardwareHash !== localHash) {
      return { valid: false, reason: '硬件指纹不匹配' };
    }
    
    // 2. 验证签名
    const publicKey = fs.readFileSync(path.resolve(process.cwd(), 'src/config/public.pem'), 'utf-8');
    
    const licenseData = {
      hardwareHash,
      encryptedExpiry
    };
    
    const licenseStr = JSON.stringify(licenseData);
    const verify = crypto.createVerify('RSA-SHA256');
    verify.update(licenseStr);
    verify.end();
    const isValid = verify.verify(publicKey, signature, 'base64');
    
    if (!isValid) {
      return { valid: false, reason: '许可证签名无效' };
    }
    
    // 3. 解密并验证敏感数据
    const { expiryDate, admin } = decryptLicenseData(encryptedExpiry, hardwareHash);
    
    // 如果是管理员账号，直接通过验证
    if (admin === true) {
      return { valid: true, reason: '管理员账号' };
    }
    
    // 4. 验证过期时间
    const now = new Date();
    const nowBJT = new Date(now.getTime() + 8 * 60 * 60 * 1000); // 当前北京时间
    
    if (nowBJT > new Date(expiryDate)) {
      return { valid: false, reason: '许可证已过期' };
    }
    
    return { valid: true, reason: '许可证校验通过' };
    
  } catch (err) {
    console.error('[错误] 许可证验证失败:', err instanceof Error ? err.message : String(err));
    return { valid: false, reason: '许可证格式错误或已损坏' };
  }
} 